// MouseStatus.cpp
//
#include "MouseStatus.h"

#include <QMouseEvent>
#include <QGraphicsSceneMouseEvent>

#include "Utils/MemCheck.h"

using namespace QtFwk;

// ------------------------------------------------------------------------------------------------
MouseStatus::MouseStatus()
{
	reset();
}

// -----------------------------------------------------------------------------------------------
template <typename T>
MouseStatus::Status MouseStatus::getButton( T *e )
{
	int btn               = ButtonNone;
	Qt::MouseButton qtbtn = Qt::NoButton;

	if( e->type() != QEvent::GraphicsSceneWheel )
		qtbtn = ((QGraphicsSceneMouseEvent*)e)->button();

	if (qtbtn & Qt::LeftButton)				btn |= ButtonLeft;
	if (qtbtn & Qt::RightButton)			btn |= ButtonRight;
	if (qtbtn & Qt::MidButton)				btn |= ButtonMiddle;

	return Status(btn);
}

// -----------------------------------------------------------------------------------------------
template <typename T>
MouseStatus::Status MouseStatus::getModifier( T *e )
{
	int mod          = ModifierNone;

	Qt::KeyboardModifiers modifiers = e->modifiers();

	if (modifiers & Qt::ShiftModifier)	 mod |= ModifierShift;
	if (modifiers & Qt::ControlModifier) mod |= ModifierCtrl;
	if (modifiers & Qt::AltModifier)	 mod |= ModifierAlt;
	if (modifiers & Qt::MetaModifier)	 mod |= ModifierMeta;
	
	return Status(mod);
}
	
// -----------------------------------------------------------------------------------------------
void MouseStatus::reset()
{
	pressedButton  = ButtonNone;
	releasedButton = ButtonNone;
	keyModifier	   = ModifierNone;
	moving         = false;
	doubleClick    = false;
	_wheel         = 0.f;
}


// -----------------------------------------------------------------------------------------------
void MouseStatus::update( QGraphicsSceneMouseEvent *e, bool updateButtons )
{
	_wheel         = 0.f;
	_prevPos       = _currPos;
	_currPos       = e->scenePos();
	moving         = (e->type() == e->GraphicsSceneMouseMove);
	releasedButton = ButtonNone;
	keyModifier	   = getModifier(e);

	if( updateButtons )
	{
		Status btn  = getButton(e);
		doubleClick = false;

		if (e->type() == QEvent::GraphicsSceneMouseDoubleClick )
		{
			doubleClick    = true;
			pressedButton |= btn;
		}
		else if (e->type() == QEvent::GraphicsSceneMousePress )
		{
			pressedButton |=   btn;
		}
		else if (e->type() == QEvent::GraphicsSceneMouseRelease )
		{
			pressedButton &= ~(btn);		
			releasedButton |= btn;
		}
	}
	
#if 0
	if( !toString().empty() )
		std::cout << toString() << std::endl;
#endif
	e->accept();
}

// -----------------------------------------------------------------------------------------------
void MouseStatus::update( QGraphicsSceneWheelEvent *e, bool updateButtons )
{
	const double WHEEL_STEP = 120.;
	const double step = e->delta() / WHEEL_STEP;

	_wheel = pow(1.25, step);
	if(_wheel > 100) _wheel = 100;
	if(_wheel < .01) _wheel = .01;
	
	keyModifier = getModifier(e);

	if( updateButtons )
	{
		Status btn = getButton(e);
			
		if (e->type() == QEvent::GraphicsSceneMousePress )
		{
			pressedButton |=   btn;
		}
		else if (e->type() == QEvent::GraphicsSceneMouseRelease )
		{
			pressedButton &= ~(btn);		
			releasedButton |= btn;
		}
	}


#if 0
	if( !toString().empty() )
		std::cout << toString() << std::endl;
#endif
	e->accept();
}

// -----------------------------------------------------------------------------------------------
unsigned int MouseStatus::getCode() const
{
	unsigned int code = 0;

	if( keyModifier & ModifierAlt   ) code |= ModifierAlt;
	if( keyModifier & ModifierCtrl  ) code |= ModifierCtrl;
	if( keyModifier & ModifierShift ) code |= ModifierShift;
	if( keyModifier & ModifierMeta  ) code |= ModifierMeta;

	if( pressedButton & ButtonLeft   ) code |= ButtonLeft;
	if( pressedButton & ButtonRight  ) code |= ButtonRight;
	if( pressedButton & ButtonMiddle ) code |= ButtonMiddle;
	
	if( pressedButton & ButtonAny  && moving ) code |= Drag;
	if( pressedButton & ButtonNone && moving ) code |= Moving;

	if( _wheel>0.f || _wheel<0.f )			   code |= Wheel;
	if( doubleClick              )             code |= DoubleClick;

	return code;
}